/*! \file HXLink.h
    \brief Head X (Synapse) interface for external processes.

	Head X | Flinders University | Martin Luerssen & Trent Lewis | 2009+
*/

#pragma once

class HXLink;

#define HXSY_NONE 0
#define HXSY_ACTIVE 1
#define HXSY_SPEAKING 2
#define HXSY_LEFTMOUSEDOWN 1
#define HXSY_RIGHTMOUSEDOWN 2
#define HXSY_MIDDLEMOUSEDOWN 4
#define HXSY_ERROR_LOAD 1
#define HXSY_ERROR_SAVE 2
#define HXSY_ERROR_PARSE 3
#define HXSY_DEAD -1
#define HXSY_BUSY 0
#define HXSY_READY 1
#define HXDYB_NONE 0
#define HXDYB_OLD 1
#define HXDYB_NEW 2

#define MAX_SYNAPSE_MORPHS 100

#include "HXPlayer.h"
#include "synapse.h"

//-----------------------------------------------------------------------------

class HXLink
{
public:
	HXLink();
	~HXLink();

	bool Connect();
	bool IsConnected() { return m_bCreatedSyns; }
	void Disconnect();

	void CheckSynapses();

	bool OpenBackground(string name, int width, int height);
	int& BackgroundStatus() { return m_backgroundStatus; }
	bool IsBackgroundModified();
	HXRGBA* GrabBackground();
	void DoneWithBackground();

	// helper methods -------------------------------------------------
	void SetVersion(int state) { m_sVersion.Write(state); }
	int GetVersion() { return m_sVersion.ReadCopy(); }
	int GetInstances() { return m_sInstances.ReadCopy(); }
	size_t GetHeadNumber() { return m_headNumber; }
	wstring GetCapabilityString();

	wstring GetCommand() { char text[MAX_TEXT_LENGTH]; m_sTextCommand.ReadArray(text); return StringToWString(string(text)); }
	void SetSpokenText(const char* text) { m_sSpokenText.WriteArray(text, strlen(text)+1); }
	void GetSpokenText(char* text) { m_sSpokenText.ReadArray(text); }
	wstring GetSpokenText() { char text[MAX_TEXT_LENGTH]; GetSpokenText(text); return StringToWString(string(text)); }
	void SetUserText(const char* text) { m_sUserText.WriteArray(text, strlen(text)+1); }
	wstring GetUserText() { char text[MAX_TEXT_LENGTH]; m_sUserText.ReadArray(text); return StringToWString(string(text)); }
	void SetDirectCommand(const char* command)  { m_sDirectCommand.WriteArray(command); }

	void SetIsReady(int state = HXSY_READY) { m_sHeadStatus.Write(state, 0); }
	void SetIsBusy() { m_sHeadStatus.Write(HXSY_BUSY, 0); }
	void SetIsDead() { SetVersion(0); SetIsTalking(0); SetIsReady(HXSY_DEAD); }
	void SetIsTalking(int state) { m_sHeadStatus.Write(state, 1); }
	bool GetIsReady() { return (m_sHeadStatus.ReadCopy(0) == HXSY_READY); }
	int GetIsTalking() { return m_sHeadStatus.ReadCopy(1); }
	void SetWordIndex(int state) { m_sHeadStatus.Write(state, 2); }
	int GetWordIndex() { return m_sHeadStatus.ReadCopy(2); }
	void SetLastError(int state) { m_sHeadStatus.Write(state, 3); }
	int GetLastError() { return m_sHeadStatus.ReadCopy(3); }
	void SetWindowToggle(int state) { m_sHeadStatus.Write(state, 4); }

	void SetKeyDown(int state) { m_sKBM.Write(state, 0); }
	void SetLastKey(int state) { m_sKBM.Write(state, 1); }
	void SetMouseDown(int state) { m_sKBM.Write(state, 2); }
	int GetMouseDown() { return m_sKBM.ReadCopy(2); }
	void SetLastMouse(int state) { m_sKBM.Write(state, 3); }
	void SetMouseDownXY(int x, int y) { m_sKBM.Write(x, 4); m_sKBM.Write(y, 5); }

	void SetWorkingPath(wstring path) { char text[MAX_PATH]; strcpy_s(text, MAX_PATH, WStringToString(path).c_str()); m_sWorkingPath.WriteArray(text, strlen(text)+1); }
	wstring GetWorkingPath() { char text[MAX_PATH]; m_sWorkingPath.ReadArray(text); return StringToWString(string(text)); }
	// helper methods -------------------------------------------------

protected:
	static DWORD WINAPI RunLinkThread(LPVOID lpParam);
	DWORD WINAPI LinkThread();
	bool CreateSynapses();
	void ReleaseSynapses();

	HANDLE m_hThread;
	bool m_bThreadExit, m_bCreatedSyns;
	int m_backgroundStatus;
	size_t m_headNumber;

	char m_linkBuffer[MAX_TEXT_LENGTH];
	float *m_pCameraLocalBuffer, *m_pCameraSynapseBuffer, *m_pMorphLocalBuffer, *m_pMorphSynapseBuffer;

	//! Number of Head X processes currently running.
	Synapse<long> m_sInstances;

	//! Version of Head.
	Synapse<long> m_sVersion;

	//! Tagged text input to Head X.
	Synapse<char> m_sTextCommand;

	//! What the Head has last said (without markup).
	Synapse<char> m_sSpokenText;

	//! User input to the Head X GUI.
	Synapse<char> m_sUserText;

	//! Head status - see Get/Set methods.
	Synapse<long> m_sHeadStatus;

	//! Viewport status - see ReadCameraLights/ChangeCameraLights methods in HXDisplay.
	Synapse<float> m_sCamera;

	//! Head blend shapes status - see Get/ChangeRemoteMorphs methods in HXDisplay.
	Synapse<float> m_sHeadMorphs;

	//! Keyboard and mouse inputs - see Get/Set methods.
	Synapse<long> m_sKBM;

	//! Current working directory.
	Synapse<char> m_sWorkingPath;

	//! Internal command trigger.
	Synapse<char> m_sDirectCommand;

	//! Background buffer.
	Synapse<HXRGBA> m_sBackground;
};

//=============================================================================

extern HXLink g_link;
